/**
 * @author shenw
 */
var Cells = function(number) {
	var that = this;
	var cells = [[],[],[],[],[],[],[],[],[]];
	var possibleMap = {};
	var puzzleList = [];
	var x = -1, y = 0, index = 0;
	
	create();
	makingPuzzle(number);
	
	//------------Public  Function-----------
	that.setCell = function(_x, _y, _value) {
		cells[_x][_y] = _value;
	};
	that.getCells = function() {
		return cells;
	};
	that.check = function() {
		console.debug('check input');
		var value;
		for (var i = 0; i < puzzleList.length; i++) {
			value = cells[puzzleList[i][0]][puzzleList[i][1]];
			if (typeof value !== 'number'
					|| isNaN(value)
					|| value < 1) {
				return false;
			}
		}
		console.debug('all input');
		for (var i=0; i<puzzleList.length; i++) {
			x = puzzleList[i][0];
			y = puzzleList[i][1];
			
			index = 0;
			console.log('check row');
			if (checkRow()) {
				console.log('check column');
				if (checkColumn()) {
					console.log('check sub cells');
					if (!checkSubCells()) {
						index = 1;
					}
				} else {
					index = 1;
				}
			} else {
				index = 1;
			}
			
			if (index === 1) {
				break;
			}
		}
		
		if (index === 0) {
			return true;
		} else {
			return false;
		}
	};
	//------------Private Function-----------
	function checkRow() {
		for (var i=1; i<10; i++) {
			if (cells[x].index(i) < 0) {
				return false;
			}
		}
		return true;
	}
	function checkColumn() {
		var list = [];
		for (var i=0; i<9; i++) {
			list.push(cells[x][i]);
		}
		for (var i=1; i<10; i++) {
			if (list.index(i) < 0) {
				return false;
			}
		}
		return true;
	}
	function checkSubCells() {
		var r, c;
		var ci, ri;
		var list = [];
		
		if (x < 3) {
			r = [0, 1, 2];
		} else if (x < 6) {
			r = [3, 4, 5];
		} else {
			r = [6, 7, 8];
		}
		
		if (y < 3) {
			c = [0, 1, 2];
		} else if (y < 6) {
			c = [3, 4, 5];
		} else if (y < 9) {
			c = [6, 7, 8];
		}
		
		for (var ci=0; ci < c.length; ci++) {
			for (var ri=0; ri < r.length; ri++) {
				if (typeof cells[r[ri]][c[ci]] === 'number') {
					list.push(cells[r[ri]][c[ci]]);
				}
			}
		}
		
		for (var i=1; i<10; i++) {
			if (list.index(i) < 0) {
				return false;
			}
		}
		return true;
	}
	function create() {
		var loop = true;
		
		while (loop) {
			switch (next()) {
				case -1:
					while(prev()) {
						// do nothing, only prve
					}
					break;
				case 1:
					break;
				case 0:
					loop = false;
					break;
			}
		}
	}
	function next() {
		if (x < 8) {
			x++;
			index++;
		} else if (y < 8) {
			x = 0;
			y++;
			index++;
		} else {
			// do thing
			return 0;
		}
		
		possibleMap[index] = {};
		possibleMap[index].list = getPossibleList();
		possibleMap[index].index = 0;
		
		if (possibleMap[index].list.length == 0) {
			return -1;
		} else {
			cells[x][y] = possibleMap[index].list[possibleMap[index].index];
			return 1;
		}
	}
	function prev() {
		cells[x][y] = 0;
		
		if (x ==0) {
			x = 8;
			y--;
		} else {
			x--;
		}
		
		index--;
		if (possibleMap[index].list.length > possibleMap[index].index + 1) {
			possibleMap[index].index++;
			cells[x][y] = possibleMap[index].list[possibleMap[index].index];
			return false;
		} else {
			return true;
		}
	}
	function getPossibleList() {
		// valid x
		var result = getPossibleRow();
		// valid y
		result = result.intersection(getPossibleColumn(cells, y), 'number');
		// valid sub
		result = result.intersection(getPossibleSubCells(cells, x, y), 'number');
		// random sort
		result = randomSort(result);
		
		return result;
	}
	function getPossibleRow() {
		var p = [1,2,3,4,5,6,7,8,9];
		
		for (var i=0; i<cells[x].length; i++) {
			if (typeof cells[x][i] === 'number') {
				p.remove(cells[x][i]);
			}
		}
		
		return p;
	}
	function getPossibleColumn() {
		var p = [1,2,3,4,5,6,7,8,9];
		
		for (var i=0; i<9; i++) {
			if (typeof cells[i][y] === 'number') {
				p.remove(cells[i][y]);
			}
		}
		
		return p;
	}
	function getPossibleSubCells() {
		var p = [1,2,3,4,5,6,7,8,9];
		var r;
		var c;
		
		if (x < 3) {
			r = [0, 1, 2];
		} else if (x < 6) {
			r = [3, 4, 5];
		} else {
			r = [6, 7, 8];
		}
		
		if (y < 3) {
			c = [0, 1, 2];
		} else if (y < 6) {
			c = [3, 4, 5];
		} else if (y < 9) {
			c = [6, 7, 8];
		}
		
		for (var ci=0; ci < c.length; ci++) {
			for (var ri=0; ri < r.length; ri++) {
				if (typeof cells[r[ri]][c[ci]] === 'number') {
					p.remove(cells[r[ri]][c[ci]]);
				}
			}
		}
		return p;
	}
	function randomSort(list) {
		var temp;
		var random;
		var length = list.length;
		
		for (var i=0; i<list.length; i++) {
			random = jshen.math.randomInteger(0, list.length - 1);
			temp = list[i];
			list[i] = list[random];
			list[random] = temp;
		}
		
		return list;
	}
	function makingPuzzle(number) {
		var pits = [];
		var r;
		var x, y;
		
		for (var i=0; i<81; i++) {
			pits.push(i);
		}
		pits = randomSort(pits);
		
		for (var i=0; i<number; i++) {
			r = pits[i];
			x = Math.floor(r / 9);
			y = r % 9;
			puzzleList.push([x, y]);
			cells[x][y] = '';
		}
	}
}
